﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;

using System.Reflection;
using System.Text;

namespace QQZiFramework
{
    public class IDBEntity
    {


        /// <summary>
        /// 属性值是否为空
        /// </summary>
        /// <param name="propertyName">属性名</param>        
        public bool ValueIsNull(string propertyName)
        {
            PropertyInfo info = this.GetType().GetProperty(propertyName);
            if (info == null) throw new Exception(propertyName + "在实体中不存在");
            return ValueIsNull(info);
        }
        

        /// <summary>
        /// 属性值是否为空
        /// </summary>
        /// <param name="proInfo">属性</param>        
        public bool ValueIsNull(PropertyInfo proInfo)
        {
            object obj = proInfo.GetValue(this, null);
            if (obj == null) return true;
            CustomerProperty cp = EntityLoaderInfo.GetEntityLoaderInfo(this.GetType()).GetCustomerProperty(proInfo.Name);
            if (cp != null && cp.Attr != null && obj.Equals(0))
            {
                if (cp.IsPrimaryKey() || cp.Attr.Usage == DBFieldUsage.ForeignKey) return true;
            }
            object[] DefaultValueAtts = proInfo.GetCustomAttributes(typeof(DefaultValueAttribute), true);
            if (DefaultValueAtts != null && DefaultValueAtts.Length > 0)
            {
                DefaultValueAttribute attr = (DefaultValueAttribute)DefaultValueAtts[0];
                if (IsNullableType(proInfo.PropertyType)) throw new Exception(proInfo.ReflectedType.Name + "." + proInfo.Name + "不能定义DefaultValue");
                if (obj.Equals(Convert.ChangeType(attr.Value, proInfo.PropertyType))) return true;
            }
            else
            {
                if (IsNullableType(proInfo.PropertyType)) return false;
                switch (proInfo.PropertyType.Name)
                {
                    case "Int32":
                        return obj.Equals(DefaultNullValue);
                    case "Int64":
                        return obj.Equals((Int64)DefaultNullValue);
                    case "Single":
                        return obj.Equals(Convert.ToSingle(DefaultNullValue));
                    case "Double":
                        return obj.Equals(Convert.ToDouble(DefaultNullValue));
                    case "Decimal":
                        return obj.Equals(Convert.ToDecimal(DefaultNullValue));
                    case "DateTime":
                        return obj.Equals(DateTime.MinValue);
                    default:
                        return false;
                }
            }
            return false;
        }

        // /// <summary>
        // /// 清除默认值，比如-99999改为0
        // /// </summary>
        // public void ClearDefaultValue()
        // {
        //     foreach (PropertyInfo proInfo in this.GetType().GetProperties())
        //     {
        //         if (!proInfo.CanWrite) continue;
        //         if (ValueIsNull(proInfo))
        //         {
        //             switch (proInfo.PropertyType.Name)
        //             {
        //                 case "Decimal":
        //                     proInfo.SetValue(this, decimal.Zero, null);
        //                     break;
        //                 case "Int32":
        //                 case "Int64":
        //                 case "Single":
        //                 case "Double":
        //                     proInfo.SetValue(this, 0, null);
        //                     break;
        //             }
        //         }
        //     }
        // }

        public static bool IsNullableType(Type theType)
        {
            return (theType.IsGenericType && theType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)));
        }
        public void SetValueDefault()
        {
            foreach (PropertyInfo proInfo in this.GetType().GetProperties())
            {
                if (!proInfo.CanWrite) continue;
                if (IsNullableType(proInfo.PropertyType)) continue;
                object[] DefaultValueAtts = proInfo.GetCustomAttributes(typeof(DefaultValueAttribute), true);
                object[] DBFieldAtts = proInfo.GetCustomAttributes(typeof(DBFieldAttribute), true);
                if (DBFieldAtts != null && DBFieldAtts.Length > 0 && ((DBFieldAttribute)DBFieldAtts[0]).Usage == DBFieldUsage.PrimaryKey) continue;
                if (DefaultValueAtts != null && DefaultValueAtts.Length > 0)
                {
                    DefaultValueAttribute attr = (DefaultValueAttribute)DefaultValueAtts[0];
                    proInfo.SetValue(this, Convert.ChangeType(attr.Value, proInfo.PropertyType), null);
                }
                // else
                // {
                //     switch (proInfo.PropertyType.Name)
                //     {
                //         case "Int32":
                //             proInfo.SetValue(this, DefaultNullValue, null);
                //             break;
                //         case "Decimal":
                //             proInfo.SetValue(this, Convert.ToDecimal(DefaultNullValue), null);
                //             break;
                //         case "Int64":
                //             proInfo.SetValue(this, Convert.ToInt64(DefaultNullValue), null);
                //             break;
                //         case "Single":
                //             proInfo.SetValue(this, Convert.ToSingle(DefaultNullValue), null);
                //             break;
                //         case "Double":
                //             proInfo.SetValue(this, Convert.ToDouble(DefaultNullValue), null);
                //             break;
                //     }
                // }
            }

        }

        /// <summary>
        /// 初始化，子类必需要调用
        /// </summary>
        public IDBEntity()
        {
            //SetValueDefault();
        }
        public object GetPrimaryValue()
        {
            CustomerProperty property = EntityLoaderInfo.GetEntityLoaderInfo(this.GetType()).PrimaryCusPro;
            return property.Info.GetValue(this, null);
        }
        public object GetPropertyValue(string name)
        {
            PropertyInfo property = this.GetType().GetProperty(name);
            return property.GetValue(this, null);
        }
        public string GetPrimaryKey()
        {
            CustomerProperty property = EntityLoaderInfo.GetEntityLoaderInfo(this.GetType()).PrimaryCusPro;
            return property.Info.Name;
        }

        /// <summary>
        /// 设置主键值，如果value为空，则不设置
        /// </summary>
        /// <param name="value"></param>
        public void SetPrimaryValue(object value)
        {
            CustomerProperty property = EntityLoaderInfo.GetEntityLoaderInfo(this.GetType()).PrimaryCusPro;
            if (value != null) property.Info.SetValue(this, value, null);
        }
        /// <summary>
        /// 从DataTable中加载第一行的值到实休
        /// </summary>        
        /// <param name="clear">是否清除实体的空值</param>
        public virtual void ParseFromTable(DataTable dt)
        {
            if (dt == null) throw new Exception("ParseFromTable dt is null");
            if (dt.Rows.Count == 0) return;
            ParseFromTableRow(dt.Rows[0]);
        }

        /// <summary>
        /// 从DataRow中加载值到实休
        /// </summary>        
        /// <param name="clear">是否清除实体的空值</param>
        public virtual void ParseFromTableRow(DataRow dr)
        {
            //if (clear) ClearDefaultValue();
            List<CustomerProperty> propertys = EntityLoaderInfo.GetEntityLoaderInfo(this.GetType()).CustomerPropertys;
            foreach (CustomerProperty cp in propertys)
            {
                if (dr.Table.Columns.IndexOf(cp.Info.Name) > -1) SetValueFromDB(cp.Info, dr[cp.Info.Name]);
            }
        }



        public void SetPropertyValue(string peopertyName, object value)
        {
            PropertyInfo info = this.GetType().GetProperty(peopertyName);
            if (info == null) throw new ClientException("没有" + peopertyName + "属性");
            SetValueFromDB(info, value);
        }

        public void SetValueFromDB(PropertyInfo info, object dbVal)
        {
            if (DBNull.Value.Equals(dbVal)) return;
            if (!info.CanWrite) return;
            if (!info.PropertyType.IsGenericType)
            {
                info.SetValue(this, Convert.ChangeType(dbVal, info.PropertyType), null);
            }
            else
            {
                //泛型Nullable<>
                Type genericTypeDefinition = info.PropertyType.GetGenericTypeDefinition();
                if (genericTypeDefinition == typeof(Nullable<>))
                {
                    info.SetValue(this, Convert.ChangeType(dbVal, Nullable.GetUnderlyingType(info.PropertyType)), null);
                }
            }
            //info.SetValue(this, convertVal, null);
        }

        /// <summary>
        /// 代表int空值，当数据库该字段可为空，或者需要序列化为null传给前端时，需要添加标记
        /// </summary> 
        public const int DefaultNullValue = -999999;

        /// <summary>
        /// 代表decimal/double等空值，当数据库该字段可为空，或者需要序列化为null传给前端时，需要添加标记
        /// </summary>
        public const double DefaultDoubleValue = -999999.0;

        public const string DbNullString = "NULL";

        /// <summary>
        /// 将实体b中不为空的值覆盖到本实例
        /// </summary>
        /// <param name="onlyNull">只覆盖空值</param>
        /// <param name="b"></param>
        public void Overwrite(IDBEntity b, bool onlyNull = false, string fileds = null)
        {
            Type type = b.GetType();
            PropertyInfo[] propertys;
            if (fileds == null || fileds == "*")
            {
                propertys = type.GetProperties();
            }
            else
            {
                string[] arr = fileds.Split(',');
                propertys = new PropertyInfo[arr.Length];
                for (int i = 0; i < arr.Length; i++)
                {
                    PropertyInfo info = type.GetProperty(arr[i]);
                    if (info == null) throw new Exception(arr[i] + "不是" + type.Name + "的属性");
                    propertys[i] = info;
                }
            }
            Type thisType = this.GetType();
            bool sameType = thisType == type;
            foreach (PropertyInfo propertyInfo in propertys)
            {
                if (!propertyInfo.CanWrite) continue;
                if (onlyNull && !ValueIsNull(propertyInfo)) continue;//如果只覆盖空值，并且本实例属性不为空，continue
                object bValue = propertyInfo.GetValue(b, null);
                if (bValue == null || b.ValueIsNull(propertyInfo)) continue;//如果b实例本属性为空，continue;
                if (sameType)
                    propertyInfo.SetValue(this, bValue, null);
                else
                {
                    PropertyInfo propertyInfoThis = thisType.GetProperty(propertyInfo.Name);
                    if (propertyInfoThis != null)
                    {
                        propertyInfoThis.SetValue(this, bValue, null);
                    }
                }
            }
        }

        public virtual string ToJson()
        {
            Newtonsoft.Json.JsonSerializerSettings settings = new Newtonsoft.Json.JsonSerializerSettings() { NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore, DefaultValueHandling = Newtonsoft.Json.DefaultValueHandling.Ignore };
            return Newtonsoft.Json.JsonConvert.SerializeObject(this, settings);
        }

    }

}
